<?php
/**
 * crcl/base
 *
 * Copyright 2013 CRCL - André Sabosch - info@crcl.de
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

namespace crcl\base\structure\field;

interface IConcrete
{
  public function set($value);
  public function get();
  public function __toString();
  public function getRaw();
  public function getLast();
  public function getRawLast();
  public function commit();
}

abstract class Base implements IConcrete
{
  public function __construct($sUri)
  {
    $oUri = \crcl\base\Resource::reader($sUri);
    $aParams = $oUri->getParams();
    if (isset($aParams[\crcl\base\structure\Field::CONFIG_DEFAULT]))
    {
      $this->default = $aParams[\crcl\base\structure\Field::CONFIG_DEFAULT];
      $this->value_last = $this->default;
      $this->value = $this->default;
    }
    if (isset($aParams[\crcl\base\structure\Field::CONFIG_PROCESSORS]))
    {
      $sProcessors = \urldecode($aParams[\crcl\base\structure\Field::CONFIG_PROCESSORS]);
      $this->aProcessors = \explode(',', $sProcessors);
    }
  }

  public function set($value)
  {
    if (!\is_null($value))
    {
      $this->check($value);
    }
    $this->value_last = $this->value;
    $this->value = $value;
    $this->bDirty = \TRUE;

    return $this->get();
  }

  public function get()
  {
    $value = $this->process($this->value);
    return $value;
  }

  public function getRaw()
  {
    return $this->value;
  }

  public function getDefault()
  {
    return $this->default;
  }

  public function getLast()
  {
    $value = $this->process($this->value_last);
    return $value;
  }

  public function getRawLast()
  {
    return $this->value_last;
  }

  public function commit()
  {
    $this->bDirty = \FALSE;
    $this->value_last = $this->value;
  }

  public function rollback()
  {
    $this->bDirty = \FALSE;
    $this->value = $this->value_last;
  }

  public function isDirty()
  {
    return $this->bDirty;
  }

  public function __toString()
  {
    return self::get();
  }

  /** PROTECTED ***********************************************************************************/

  protected $value = \NULL;
  protected $value_last = \NULL;
  protected $default = \NULL;

  protected $aProcessors = array();

  protected $bDirty = \FALSE;

  //@codeCoverageIgnoreStart
  abstract protected function check($value);
  //@codeCoverageIgnoreEnd

  /** PRIVATE *************************************************************************************/

  private function process($value)
  {
    foreach ($this->aProcessors as $sProcessor)
    {
      $sScheme = \crcl\base\resource\Utils::getScheme($sProcessor);
      switch ($sScheme)
      {
        case 'filter':
          $sFilter = \substr($sProcessor, 9);  //strlen('filter://')
          $oFilter = \crcl\base\Filter::getInstance($sFilter);
          $value = $oFilter->filter($value);
          break;
        case 'validator':
          $sValidator = \substr($sProcessor, 12);  //strlen('validator://')
          $oValidator = \crcl\base\Validator::getInstance($sValidator);
          $oValidator->test($value);
          break;
        default:
          throw new Exception('Invalid processor.', Exception::ERROR_INVALIDPROCESSOR);
      }
    }
    return $value;
  }
}